#include <string>
#include <unordered_map>
#include 
#include "misc.hpp"
#include "mandarava/iocp.hpp"

miocp :: miocp( int maxThd ):m_cmpt_port__( nullptr ),m_max_thds__( maxThd ),m_is_running__( false )
{
	 WSADATA wsaData;
	 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		 throw std::runtime_error( "Failed to initialize winsock." );
	 }

	 // 创建完成端口
	 m_cmpt_port__ = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0);
	 if( m_cmpt_port__.load() == nullptr) {
		 throw std::runtime_error( "Failed to create completion port." );
	 }
}

miocp :: ~miocp()
{
	stop__();
	
	closeHandle( m_cmpt_port__.load() );
	WSACleanup();
}

void miocp :: start__()
{
	m_is_running__ = true;

	while( m_is_running__.load() ){
		DWORD count = 0;
		ULONG_PTR key = 0;
		LPOVERLAPPED overlapped = nullptr;

		// 等待IO完成
		if (GetQueuedCompletionStatus( m_cmpt_port__.load(), &count, &key, &overlapped, INFINITE)) {
			WSAOVERLAPPED* wsaOverlapped = reinterpret_cast<WSAOVERLAPPED*>(overlapped);
			HANDLE h = reinterpret_cast<HANDLE>(wsaOverlapped->hEvent);
			// 找到接口开始执行
			auto it = m_channels__.find( h );
			if( it != m_channels__.end() ){
				it-second->onReadyRead( nullptr , len );
			}
		}else {      // 错误处理
                        DWORD errorCode = GetLastError();
                        if (overlapped) {
				HandleError(completionKey, errorCode);
                        }
		}
	}
}

void miocp :: stop__()
{
	m_is_running__ = false;

	std::unique_lock< std::mutex > lck( m_mutex__ );
	
	for( auto it = m_channels__.begin(); it != m_channels__.end(); it ++ ){
		if( it -> second ){
			HANDLE rc = CreateIoCompletionPort( it->second->native_handle() , nullptr , nullptr , 0);
			if( rc == nullptr ){
				ERROR_MSG( "" );
			}
		}
	}	
}

void miocp :: start__()
{
	m_is_running__ = false;

	std::unique_lock< std::mutex > lck( m_mutex__ );
	
	for( auto it = m_channels__.begin(); it != m_channels__.end(); it ++ ){
		if( it -> second ){
			HANDLE rc = CreateIoCompletionPort( it->second->native_handle() , m_cmpt_port__.load() , nullptr , 0);
			if( rc == nullptr ){
				ERROR_MSG( "" );
			}
		}
	}	
}
	
bool miocp :: addChannel( dataCh * ch )
{
	if( ch == nullptr ){
		return false;
	}
	HANDLE rc = CreateIoCompletionPort( ch->native_handle() , m_cmpt_port__.load() , nullptr , 0);
	if( rc == NULL ){
		return false;
	}

	std::unique_lock< std::mutex > lck( m_mutex__ );

	m_channels__.insert( std::make_pair( ch->native_handle() , ch ) );
	return true;
}

bool miocp :: eraseChannel( dataCh * ch )
{
	if( ch == nullptr ){
		return false;
	}
	std::unique_lock< std::mutex > lck( m_mutex__ );

	auto it = m_channels__.find( ch->native_handle() );

	if( it == m_channels__.end() ){ return false;}

	HANDLE rc = CreateIoCompletionPort( ch->native_handle() , nullptr , nullptr , 0);
	if( rc == NULL ){
		return false;
	}

	m_channels__.erase( it );
	
	return true;
}

void miocp :: run( bool sw , long overtime )
{
	UNUSED( overtime );
	if( sw == m_is_running__ ) return;

	if( sw ){
		start__();
	}else{
		stop__();
	}
}

